/*
 * Enumeration.h
 *
 *  Created on: 7 dec 2011
 *      Author: ytc0039
 */

#ifndef ENUMERATION_H_
#define ENUMERATION_H_

#include <stddef.h>
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>

using namespace std;

template< class enumClass>
class Enumeration{
public:
	struct NameValuePair {
	     	 	enumClass   *value_;
	        	std::string *image_;

	        	NameValuePair( enumClass *value, const char *image )
	        		: value_(value), image_( new std::string( image ) ) {
	        	}
	        };



	typedef typename std::vector<NameValuePair> InstancesVector;

	typedef typename std::vector<NameValuePair>::const_iterator InstancesVectorConstIterator;
	typedef typename std::vector<NameValuePair>::iterator InstancesVectorIterator;

	        class Iterator {
	        	public:
	        		Iterator( const Iterator &other ) : iterator_(other.iterator_) {}
	        		void operator=( const Iterator &other ) { iterator_ = other.iterator_; }
	        		Iterator operator++(int) { Iterator old(*this);
												++iterator_;
												return old;
	        		}
	        		Iterator &operator++() { ++iterator_; return *this; }
	        		bool operator!=( const Iterator &other ) { return iterator_ != other.iterator_; }
	        		const enumClass &operator*() { return *(*iterator_).value_; }

	        		// Type information for the iterator_traits
	        		typedef std::forward_iterator_tag iterator_category;
	        		typedef const enumClass& value_type;
	        		typedef ptrdiff_t difference_type;
	        		typedef enumClass* pointer;
	        		typedef const enumClass& reference;

	        	private:
	        		friend class Enumeration;
	        		Iterator( typename InstancesVector::iterator &iterator ) : iterator_(iterator) {}
	        		typename InstancesVector::iterator iterator_;
	        };

protected:
	Enumeration(const char* Image);


public :

		static inline int size();

        // Returns an iterator to the first enum value.
        //## operation begin()
        static typename Enumeration<enumClass>::Iterator begin();

        // Returns an iterator which defined the end of the enums. Note that this is not dereferentialble (as usual in STL).
        //## operation end()
        static typename Enumeration<enumClass>::Iterator end();

        // Returns the first of the enumerated values.
        //## operation first()
        inline static const enumClass& first();

        // Returns the enum value for the given ordinal. An assertion will fail if ordinal is not within range. Check with method isOrdinalInRange() if you don't know.
        //## operation fromOrdinal(unsigned char)
        inline static const enumClass& fromOrdinal(unsigned char ordinalValue);

        // Attempts to parse the passed string as an enum value. If the string does not match any enum value, the success parameter is set to false and the enumValue parameter is untouched. Otherwise the success parameter sis set to true and the enumValue parameter is updated with the correct value.
        //
        // Character case does not matter.
        //## operation fromString(string,bool,enumClass)
        static void fromString(const string& image, bool& success, enumClass& enumValue);

        // Return true if the given ordinal is within the range of the enumerated type.
        //## operation isOrdinalInRange(unsigned char)
        inline static bool isOrdinalInRange(unsigned char ordinalValue);

        // Returns the last of the enumerated values.
        //## operation last()
        inline static const enumClass& last();

        //## operation operator!=(Enumeration) const
        inline bool operator!=(const Enumeration<enumClass>& other) const;

        //## operation operator<(Enumeration) const
        inline bool operator<(const Enumeration<enumClass>& other) const;

        //## operation operator<=(Enumeration) const
        inline bool operator<=(const Enumeration<enumClass>& other) const;

        //## operation operator==(Enumeration) const
        inline bool operator==(const Enumeration<enumClass>& other) const;

        //## operation operator>(Enumeration) const
        inline bool operator>(const Enumeration<enumClass>& other) const;

        //## operation operator>=(Enumeration) const
        inline bool operator>=(const Enumeration<enumClass>& other) const;

        inline const enumClass& operator[] (unsigned char val) const;

        //## operation ordinal() const
        inline unsigned char ordinal() const;

        // Returns the previous enumvalue before this one. Note that it is not allowed to perform this on the first enum value.
        //## operation predecessor() const
        inline const enumClass& predecessor() const;

        // Returns the next enumvalue after this one. Note that it is not allowed to perform this on the last enum value.
        //## operation successor() const
        inline const enumClass& successor() const;

        //## operation toString() const
        inline string& toString() const;


#include <boost/algorithm/string.hpp>

private:
	static typename Enumeration<enumClass>::InstancesVector* instances_;

	unsigned char ordinal_;

};

//----------------------------------------------------------------------------
// inline operations for Enumeration
//----------------------------------------------------------------------------

template <class enumClass> inline const enumClass& Enumeration<enumClass> ::first() {
   //#[ operation first()


   return *(instances_->front().value_);
   //#]
}

template <class enumClass> inline const enumClass& Enumeration<enumClass> ::fromOrdinal(unsigned char ordinalValue) {
   //#[ operation fromOrdinal(unsigned char)


   return *((*instances_)[ordinalValue].value_);
   //#]
}

template <class enumClass> inline bool Enumeration<enumClass> ::isOrdinalInRange(unsigned char ordinalValue) {
   //#[ operation isOrdinalInRange(unsigned char)


   return ordinalValue < instances_->size();
   //#]
}

template <class enumClass> inline const enumClass& Enumeration<enumClass> ::last() {
   //#[ operation last()


   return *(instances_->back().value_);
   //#]
}

template <class enumClass> inline bool Enumeration<enumClass> ::operator!=(const Enumeration<enumClass>& other) const {
   //#[ operation operator!=(Enumeration) const
   return ordinal_ != other.ordinal_;
   //#]
}

template <class enumClass> inline bool Enumeration<enumClass> ::operator<(const Enumeration<enumClass>& other) const {
   //#[ operation operator<(Enumeration) const
   return ordinal_ < other.ordinal_;
   //#]
}

template <class enumClass> inline bool Enumeration<enumClass> ::operator<=(const Enumeration<enumClass>& other) const {
   //#[ operation operator<=(Enumeration) const
   return ordinal_ <= other.ordinal_;
   //#]
}

template <class enumClass> inline bool Enumeration<enumClass> ::operator==(const Enumeration<enumClass>& other) const {
   //#[ operation operator==(Enumeration) const
   return ordinal_ == other.ordinal_;
   //#]
}

template <class enumClass> inline bool Enumeration<enumClass> ::operator>(const Enumeration<enumClass>& other) const {
   //#[ operation operator>(Enumeration) const
   return ordinal_ > other.ordinal_;
   //#]
}

template <class enumClass> inline bool Enumeration<enumClass> ::operator>=(const Enumeration<enumClass>& other) const {
   //#[ operation operator>=(Enumeration) const
   return ordinal_ == other.ordinal_;
   //#]
}

template <class enumClass> inline const enumClass& Enumeration<enumClass> ::operator[](unsigned char val) const
{


	return fromOrdinal(val);
}


template <class enumClass> inline unsigned char Enumeration<enumClass> ::ordinal() const {
   //#[ operation ordinal() const
   return ordinal_;
   //#]
}

template <class enumClass> inline const enumClass& Enumeration<enumClass> ::predecessor() const {
   //#[ operation predecessor() const
   return *((*instances_)[ordinal_ - 1].value_);
   //#]
}

template <class enumClass> inline const enumClass& Enumeration<enumClass> ::successor() const {
   //#[ operation successor() const
   return *((*instances_)[ordinal_ + 1].value_);
   //#]
}

template <class enumClass> inline string& Enumeration<enumClass> ::toString() const {
   //#[ operation toString() const
   return *(*instances_)[ordinal_].image_;
   //#]
}


template <class enumClass> inline int Enumeration<enumClass> ::size(){

	return instances_->size();
}






/**
 * \brief Hairy declaration
 *
 * What does this say?? Well...Lets divide it in several layers.
 *
 * \code
 * template <class enumClass>
 * \endcode
 * To know that there exists a template
 * \code
 * typename Util::Enumeration<enumClass>::InstancesVector * Enumeration<enumClass> ::instances_( NULL );
 * \endcode
 * Set the static instance to NULL.
 */
template <class enumClass>
typename Enumeration<enumClass>::InstancesVector * Enumeration<enumClass> ::instances_( NULL );

/**
 * \brief constructor with parameter.
 *
 * the image is inserted into the instance vector.
 * @param image
 */
template <class enumClass> Enumeration<enumClass> ::Enumeration(const char * image) : ordinal_( instances_ ? instances_->size() : 0 )  {

        if (!instances_) {
        	instances_ = new InstancesVector();
        }


        instances_->push_back( NameValuePair( static_cast<enumClass*>(this), image ) );

        //#]
    }


template <class enumClass> typename Enumeration<enumClass>::Iterator Enumeration<enumClass> ::begin() {
       //#[ operation begin()
       InstancesVectorIterator it = instances_->begin();
       return Iterator( it );
       //#]
  }

template <class enumClass> typename Enumeration<enumClass>::Iterator Enumeration<enumClass> ::end() {
   //#[ operation end()
   InstancesVectorIterator it = instances_->end();
   return Iterator( it );
   //#]
}

template <class enumClass> void Enumeration<enumClass> ::fromString(const string& image, bool& success, enumClass& enumValue) {
        //#[ operation fromString(string,bool,enumClass)
        success = false;

        for (InstancesVectorConstIterator value = instances_->begin(); value != instances_->end(); ++value) {
         	if (boost::iequals( image, *(*value).image_ )) {
         		success = true;
         		enumValue = *((*value).value_);
         		return;
         	}
        }
}


#endif /* ENUMERATION_H_ */
